package com.liuya.safe.policy.controller;

import com.liuya.common.exception.EntityExistException;
import com.liuya.common.WebUtil;
import com.liuya.safe.exception.AuthException;
import com.liuya.safe.model.SafeQuery;
import com.liuya.safe.policy.handler.QueryDesignHandler;
import com.liuya.safe.policy.handler.QueryRawHandler;
import com.liuya.safe.policy.handler.QueryTestHandler;
import com.liuya.safe.policy.service.QueryManagerService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.util.Map;

import com.liuya.db.sql.xml.QueryType;
import com.liuya.entitle.QueryResult;

import com.liuya.common.SpringUtils;
import com.liuya.safe.model.SafeUser;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 查询策略测试
 */
@Controller
@Api(value = "查询测试", description = "查询测试")
@RequestMapping(value = "queryTest")
public class QueryTestController extends AbstractTestController {
    private static final Log log = LogFactory.getLog(QueryTestController.class);
    private static final int DEFAULT_QUERY_RESULT_PAGE_SIZE = 15;

    @ApiOperation(value = "直接跳到test界面")
//    @RequiresPermissions("sys.queryTest.testPolicy")
    @RequestMapping(value = "/testPolicy")
    public Object testPolicy(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        QueryTestHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        String id = WebUtil.getStringParameter(req, "id", "0");
        modelMap.addAttribute("id", id);
        return "policy/query/test";
    }

    @ApiOperation(value = "测试执行完成，返回查询主页面")
//    @RequiresPermissions("sys.queryPolicy.return")
    @RequestMapping(value = "/returnQuery")
    public Object returnQuery(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        QueryTestHandler handler = getHandler(req);
        req.setAttribute("handler", handler);
        // remove handler from session
        req.getSession().removeAttribute(getHandlerAttributeKey(req));
        modelMap.addAttribute("id", WebUtil.getStringParameter(req, "id", "0"));
        // goto manage page
//        return "redirect:/queryMng/openTree.do";
        return "redirect:/queryDesign/editPolicy.do";
    }

    @ApiOperation(value = "运行测试")
//    @RequiresPermissions("sys.queryPolicy.runTest")
    @RequestMapping(value = "/runTest")
    public Object runTest(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap) throws IOException{
        String oper = req.getParameter("oper");
        QueryTestHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        if (log.isDebugEnabled()) {
            log.debug("oper=" + oper + ", query=" + handler.getQuery().getName());
        }

        boolean testUserNeeded = handler.isTestUserNeeded();
        String[] testContextFields = handler.getTestContextFields();
        SafeUser testUser = buildTestUser(req, testUserNeeded);

        Map testCtx = null;
        try {
            testCtx = buildTestContext(req, testContextFields);
        } catch (Exception e) {
            log.error(e);
        }

        int first = WebUtil.getIntParameter(req, "first", 0);
        QueryResult testResult;
        try {
            testResult = handler.run(testUser, testCtx, first, DEFAULT_QUERY_RESULT_PAGE_SIZE);
            req.setAttribute("testResult", testResult);

            return "policy/query/testResult";
        } catch (Exception e) {
            PrintWriter writer = rep.getWriter();
            writer.write("<font color='red'><pre>");
            e.printStackTrace(writer);
            writer.write("</pre></font>");
        }
        return "";
    }

    @ApiOperation(value = "保存")
//    @RequiresPermissions("sys.queryPolicy.save")
    @RequestMapping(value = "/save")
    @ResponseBody
    public Object save(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        QueryTestHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        if (log.isDebugEnabled()) {
            log.debug("oper=" + oper + ", query=" + handler.getQuery().getName());
        }

        boolean testUserNeeded = handler.isTestUserNeeded();
        String[] testContextFields = handler.getTestContextFields();

        // remove handler from session
        req.getSession().removeAttribute(getHandlerAttributeKey(req));

        String id = WebUtil.getStringParameter(req, "id", "-23");
        QueryManagerService queryManager = (QueryManagerService) SpringUtils.getBean("queryManagerService");
        try {
            handler.save(id, queryManager);
            updateHandler(req, handler);
        } catch (EntityExistException e) {
            log.error("", e);
        }

        return true;
    }

    private void updateHandler(HttpServletRequest req, Object handler){
        String key = getHandlerAttributeKey(req);
        req.getSession().setAttribute(key, handler);
    }

    public QueryTestHandler createHandler(HttpServletRequest req) {
        String id = WebUtil.getStringParameter(req, "id", "0");
        QueryManagerService queryManager = (QueryManagerService) SpringUtils.getBean("queryManagerService");
        SafeQuery query = queryManager.getQuery(id);

        com.liuya.db.sql.xml.QueryType xmlQuery;
        try {
            xmlQuery = com.liuya.db.sql.xml.Query.unmarshal(new StringReader(query.getXmlContent()));
        } catch (Exception e) {
            throw new AuthException(e);
        }

        return new QueryTestHandler(xmlQuery);
    }

    public String getHandlerAttributeKey(HttpServletRequest req) {
        int id = WebUtil.getIntParameter(req, "id", 0);
        return "_$safeQuery_" + id;
    }

    private QueryTestHandler getHandler(HttpServletRequest req) {
        String oper = req.getParameter("oper");
        String key = getHandlerAttributeKey(req);
        Object obj = req.getSession().getAttribute(key);
        QueryTestHandler handler = null;

        if (obj == null || "loadFresh".equals(oper)) {
            handler = createHandler(req);

            // save into session, will be removed when policy is saved
            req.getSession().setAttribute(key, handler);
        } else if (obj instanceof QueryDesignHandler) {
            QueryDesignHandler designHandler = (QueryDesignHandler) obj;
            QueryType query = designHandler.getQuery();
            handler = new QueryTestHandler(query);
            req.getSession().setAttribute(key, handler);
        } else if (obj instanceof QueryRawHandler) {
            QueryRawHandler rawHandler = (QueryRawHandler) obj;
            QueryType query = rawHandler.getQuery();
            handler = new QueryTestHandler(query);
            req.getSession().setAttribute(key, handler);
        } else {
            handler = (QueryTestHandler) obj;
        }

        return handler;
    }
}
